package com.smart.cosstarter.config;

import com.smart.cosstarter.exception.NoBucketExeception;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.Copy;
import com.qcloud.cos.transfer.Download;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;

import java.io.File;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: jj
 * @Date: 2019/8/6 17:57
 * @Version 1.0
 */
public class COSObjectManager {

	private COSClient cosClient;

	public COSObjectManager(COSClient cosClient) {
		this.cosClient = cosClient;
	}

	// 线程池大小，建议在客户端与 COS 网络充足(如使用腾讯云的 CVM，同地域上传 COS)的情况下，设置成16或32即可, 可较充分的利用网络资源
	// 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
	private static ExecutorService threadPool = null;

	private static ExecutorService createThreadPool(){
		if (threadPool == null){
			threadPool = Executors.newFixedThreadPool(32);
		}
		if (threadPool.isShutdown()){
			threadPool = Executors.newFixedThreadPool(32);
		}
		return threadPool;
	}

	public ObjectListing listObjects(ListObjectsRequest listObjectsRequest) throws CosClientException {
		return cosClient.listObjects(listObjectsRequest);
	}

	public ObjectListing listObjects(String bucketName, String prefix, String marker, String delimiter, Integer maxKeys)
			throws CosClientException, CosServiceException {
		ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
		// 设置bucket名称
		if (bucketName == null) {
			throw new NoBucketExeception();
		}
		listObjectsRequest.setBucketName(bucketName);
		// prefix表示列出的object的key以prefix开始
		if (prefix != null && !"".equals(prefix)) {
			listObjectsRequest.setPrefix(prefix);
		} else {
			listObjectsRequest.setPrefix("/");
		}
		// 标记 list 的起点位置，第一次可设置为空，后续请求需设置为上一次 listObjects 返回值中的 nextMarker
		if (marker != null && !"".equals(marker)) {
			listObjectsRequest.setMarker(marker);
		}
		// deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
		if (delimiter != null && !"".equals(delimiter)) {
			listObjectsRequest.setDelimiter(delimiter);
		} else {
			listObjectsRequest.setDelimiter("/");
		}
		// 设置最大遍历出多少个对象, 一次listobject最大支持1000
		if (maxKeys != null && maxKeys >= 0) {
			listObjectsRequest.setMaxKeys(maxKeys);
		} else {
			listObjectsRequest.setMaxKeys(1000);
		}
		return cosClient.listObjects(listObjectsRequest);
	}

	// 上传对象
	public UploadResult synchUpload(final PutObjectRequest putObjectRequest) throws InterruptedException, CosClientException {
		if (threadPool.isShutdown()){

		}

		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		upload.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 上传对象
	public UploadResult asynchUpload(final PutObjectRequest putObjectRequest) throws InterruptedException, CosClientException {
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 上传对象
	public UploadResult synchUpload(String bucketName, String key, File file) throws InterruptedException, CosClientException {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		upload.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 上传对象
	public UploadResult asynchUpload(String bucketName, String key, File file) throws InterruptedException, CosClientException {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 上传对象
	public UploadResult synchUpload(String bucketName, String key, InputStream input, ObjectMetadata metadata) throws InterruptedException, CosClientException {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, input, metadata);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		upload.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 上传对象
	public UploadResult asynchUpload(String bucketName, String key, InputStream input, ObjectMetadata metadata) throws InterruptedException, CosClientException {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, input, metadata);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 本地文件上传
		Upload upload = transferManager.upload(putObjectRequest);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		UploadResult uploadResult = upload.waitForUploadResult();
		// 关闭 TransferManger
		transferManager.shutdownNow();

		return uploadResult;
	}

	// 下载对象
	public Download synchDownload(final GetObjectRequest getObjectRequest, final File file) throws InterruptedException, CosClientException {
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		download.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	// 下载对象
	public Download asynchDownload(final GetObjectRequest getObjectRequest, final File file) throws CosClientException {
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	// 下载对象
	public Download synchDownload(String bucketName, String key, final File file) throws InterruptedException, CosClientException {
		GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		download.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	// 下载对象
	public Download asynchDownload(String bucketName, String key, final File file) throws CosClientException {
		GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	// 下载对象
	public Download synchDownload(String bucketName, String key, Long[] range, final File file) throws InterruptedException, CosClientException {
		GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
		getObjectRequest.setRange(range[0], range[1]);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
		download.waitForCompletion();
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	// 下载对象
	public Download asynchDownload(String bucketName, String key, Long[] range, final File file) throws CosClientException {
		GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
		getObjectRequest.setRange(range[0], range[1]);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		// 下载文件
		Download download = transferManager.download(getObjectRequest, file);
		// 关闭 TransferManger
		transferManager.shutdownNow();
		return download;
	}

	public COSObject getObject(GetObjectRequest getObjectRequest) throws CosClientException{
		COSObject cosObject = cosClient.getObject(getObjectRequest);
		return cosObject;
	}

	public COSObject getObject(String bucketName, String key) throws CosClientException{
		GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
		COSObject cosObject = cosClient.getObject(getObjectRequest);
		return cosObject;
	}

	public CopyResult copy(final CopyObjectRequest copyObjectRequest) throws CosClientException, InterruptedException {
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		Copy copy = transferManager.copy(copyObjectRequest, cosClient, null);
		// 返回一个异步结果 copy, 可同步的调用 waitForCopyResult 等待 copy 结束, 成功返回 CopyResult, 失败抛出异常.
		CopyResult copyResult = copy.waitForCopyResult();
		return copyResult;
	}

	public CopyResult copy(String sourceBucketRegion,
	                       String sourceBucketName,
	                       String sourceKey,
	                       String destinationBucketName,
	                       String destinationKey) throws CosClientException, InterruptedException {
		CopyObjectRequest copyObjectRequest = new CopyObjectRequest(new Region(sourceBucketRegion), sourceBucketName,
				sourceKey, destinationBucketName, destinationKey);
		// 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosClient, createThreadPool());
		Copy copy = transferManager.copy(copyObjectRequest, cosClient, null);
		// 返回一个异步结果 copy, 可同步的调用 waitForCopyResult 等待 copy 结束, 成功返回 CopyResult, 失败抛出异常.
		CopyResult copyResult = copy.waitForCopyResult();
		return copyResult;
	}

	public void deleteObject(String bucketName, String key) throws CosClientException {
		cosClient.deleteObject(bucketName, key);
	}


}
